﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DadaLib
{
    /// <summary>
    /// A string list with weight information for elements.
    /// </summary>
    [Serializable]
    public class WeightedStringList
    {
        /// <summary>
        /// Total number of words processed.
        /// </summary>
        private int totalNumber;

        /// <summary>
        /// Internal Dictionary mapping words to number of apperances.
        /// </summary>
        private SortedDictionary<string, int> _wordToCount;

        /// <summary>
        /// Random number generator.
        /// </summary>
        [NonSerialized]
        private Random _rnd;

        /// <summary>
        /// Initializes a new instance of the <see cref="WeightedStringList"/> class.
        /// </summary>
        public WeightedStringList()
        {
            _rnd = new Random();
            totalNumber = 0;
            _wordToCount = new SortedDictionary<string, int>();
        }

        /// <summary>
        /// Inserts the specified word.
        /// </summary>
        /// <param name="word">The word.</param>
        public void Insert(string word)
        {
            if (!_wordToCount.Keys.Contains(word))
                _wordToCount[word] = 0;
            _wordToCount[word]++;
            totalNumber++;
        }

        /// <summary>
        /// Sorts the internal dictionary.
        /// </summary>
        public void Sort()
        {
            var sortedWords = from keyValue in _wordToCount orderby keyValue.Value descending select keyValue.Key;
            var newWordToCount = new SortedDictionary<string, int>();
            foreach (var word in sortedWords)
                newWordToCount[word] = _wordToCount[word];
            _wordToCount = newWordToCount;
        }

        /// <summary>
        /// Gets a string without considering weight.
        /// </summary>
        /// <returns></returns>
        public string GetRandomString()
        {
            var wordCount = _wordToCount.Keys.Count;
            var pos = _rnd.Next(wordCount);
            var word = _wordToCount.Keys.ElementAt(pos);
            return word;
        }

        /// <summary>
        /// Gets the weighted random string.
        /// </summary>
        /// <returns></returns>
        public string GetWeightedRandomString()
        {
            if (_rnd == null)
                _rnd = new Random(DateTime.Now.Millisecond);
            var wordCount = _wordToCount.Keys.Count;
            var index = _rnd.Next(totalNumber);
            var upperLimit = 0;
            foreach (var word in _wordToCount.Keys)
            {
                upperLimit += _wordToCount[word];
                if (index < upperLimit)
                    return word;
            }
            return null;
        }


    }

}
